<!DOCTYPE html>
<html lang="en-us">
  <head>
  <meta http-equiv="content-type" content="text/html;charset=utf-8">
  <meta http-equiv="X-UA-Compatible" content="chrome=1">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="robots" content="noodp"/>
  <meta name="author" content="Mr.wei">
  
  
  
  <link rel="prev" href="http://blog.mr-wei.cn/2019/shell-%E9%80%9A%E9%85%8D%E7%AC%A6/" />
  <link rel="next" href="http://blog.mr-wei.cn/2019/cadence-allegro%E5%88%B6%E4%BD%9C%E9%80%9A%E5%AD%94%E7%84%8A%E7%9B%98/" />
  <link rel="canonical" href="http://blog.mr-wei.cn/2019/linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BB%88%E7%AB%AF/" />
  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
  <link rel="manifest" href="/site.webmanifest">
  <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
  <meta name="msapplication-TileColor" content="#da532c">
  <meta name="theme-color" content="#ffffff">
  <title>
       
       
           Linux系统编程之终端 | Mr.wei
       
  </title>
  <meta name="title" content="Linux系统编程之终端 | Mr.wei">
    
  
  <link rel="stylesheet" href="/font/iconfont.css">
  <link rel="stylesheet" href="/css/main.min.css">


  
  
 

<script type="application/ld+json">
 "@context" : "http://schema.org",
    "@type" : "BlogPosting",
    "mainEntityOfPage": {
         "@type": "WebPage",
         "@id": "http:\/\/blog.mr-wei.cn"
    },
    "articleSection" : "posts",
    "name" : "Linux系统编程之终端",
    "headline" : "Linux系统编程之终端",
    "description" : "终端驱动程序的两种模式  规范模式 : 在此种模式下，终端的输入是按照行来处理的，而且可进行编辑操作。每一行都由换行符来结束，当用户按下回车键时可产生换行符。在终端上执行的read()调用只会在一行输入完成之后才回返回，且最多只返回一行。如果read()请求的字节数少于当前行中的可用字节，那么剩下的字节在下次read()调用时可用。\n 非规范模式 : 终端输入不会被装配成行。不需要用户按下回车键就能读取到单个字符。c_cc数组中的元素TIME以十分之一秒为单位来指定超时时间。元素MIN指定了被读取字节数的最小值。\n MIN==0,TIME==0(轮询读取)  如果在调用过程中有数据可用，那么read()将立刻返回可用的字节数和所请求的字节数中较小的那个值。如果没有数据可用，read()将立即返回0。\n MIN\x26gt;0,TIME==0(阻塞式读取,open不指定O_NONBLOCK标志)  read()会阻塞，直到请求的字节数得到满足或者读取到了MIN个字节，此时就返回这两者中较小的那一个。\n MIN==0,TIME\x26gt;0(带有超时机制的读操作,open不指定O_NONBLOCK标志)  调用read()时会启动一个定时器。当至少有一个字节可用，或者当经历了TIME个十分之一秒后，read()会立刻返回。在后一种情况下read()将返回0。\n MIN\x26gt;0,TIME\x26gt;0(既有超时机制又有最小读取字节要求,open不指定O_NONBLOCK标志)  当输入的首个字节可用后，之后每接收到一个字节就重启定时器。如果读到了MIN个字节，或者请求的字节数已经读取完毕，此时read()会返回两者间较小的那个值。或者当接收连续字节之间的时隙超过TIME个十分之一秒，此时read()会返回0。因为定时器只会初始字节可用后才启动，因此至少可以返回1个字节。\n  获取和修改终端属性 #include \x26lt;termios.h\x26gt; int tcgetattr(int fd,struct termios *termios_p);\/\/获取终端属性 int tcsetattr(int fd,int optional_actions,const struct termios *termios_p);\t\/\/设置终端属性 \/\/fd为终端文件描述符，如果fd不指向终端，调用函数会失败并伴随错误码ENOTTY \/\/termios_p为指向结构体termios的指针用来记录终端的各项属性 \/\/optional_action 决定设置的属性何时生效 \/\/函数调用成功返回0，失败返回-1  termios结构体详解 struct termoios{ tcflag_t c_iflag;\t\/\/控制终端输入的标志 tcflag_t c_oflag;\t\/\/控制终端输出的标志 tcflag_t c_cflag;\t\/\/控制终端线速的硬件控制相关的标志 tcflag_t c_lflag;\t\/\/控制终端输入的用户界面的标志 cc_t c_line;\t\/\/指定终端的行规程 cc_t c_cc[NCCS];\t\/\/包含终端的特殊字符，以及用来控制非规范模式下输入操作的相关字段 speed_t c_ispeed;\t\/\/Linux未使用 speed_t c_ospeed;\t\/\/Linux未使用 } }  c_iflag    标志 描述 默认设置     BRKINT 在BREAK状态下发出信号终端 打开    在输入中将CR映射为NL 打开    忽略BREAK状态 关闭   IGNCR 在输入中忽略CR 关闭    忽略有奇偶校验错误的字符 关闭    终端输入队列满时发出响铃(未使用) (打开)   INLCR 在输入中将NL映射为CR 关闭    开启输入奇偶校验检查 关闭    从输入字符中去掉最高位 关闭   IUTF8 输入为UTF-8编码 关闭    如果IEXTEN也同时设置，则在输入中将大写字符映射为小写字符 关闭   I 允许用任意字符来重启已停止的输出 关闭    c_oflag    标志 描述 默认设置     BSDLY 退格延时掩码(BS0、BS1) BS0   CRDLY CR延时掩码(CR0、CR1、CR2、CR3) CR0   FFDLY 换页符延时掩码(FF0、FF1) FF0   NLDLY 换行延时掩码(NL0、NL1) NL0   OCRNL 在输出中将CR映射为NL 关闭   OFDEL 用DEL作为填充符否则用NULL作为填充符 关闭   OFILL 采用填充符作为延时而不是定时延时 关闭   OLCUC 在输出中将小写字符映射为大写字符 关闭   ONLCR 在输出中将NL映射为CR-NL 打开   ONLRET 假定NL执行CR的功能 关闭   ONOCR 如果已经在一行的开始就不输出CR 关闭   OPOST 执行输出后续处理 打开    水平制表符延时掩码(TAB0、TAB1、TAB2、TAB3) TAB0   VTDLY 垂直制表符延时掩码(VT0、VT1) VT0    c_cflag    标志 描述 默认设置     CBAUD 波特率掩码 B38400   CBAUDEX 扩展波特率掩码针速率对大于38400 关闭   CIBAUD 输入波特率(未使用) 关闭   CLOCAL 忽略调制解调器的状态行 关闭   CMSPAR 使用奇偶校验 关闭   CREAD 允许输入被接收 打开   CRTSCTS 启动CTS\/RTS流控 关闭   CSIZE 字符大小掩码(CS5、CS6、CS7、CS8) CS8   CSTOPB 每个字符使用两个停止位，否则使用1个 关闭   HUPCL 在上次关闭时挂起 打开   PARENB 启动奇偶校验 关闭   PARODD 使用奇数校验否则使用偶数校验 关闭    c_lflag    标志 描述 默认设置     ECHO 回显输入字符 打开   ECHOCTL 以可视方式回显控制字符 打开   ECHOE 以可视方式回显ERASE字符 打开   ECHOK 以可视方式回显KILL字符 打开   ECHOKE 在回显KILL字符后不输出新的行 打开   ECHONL 回显NL即使禁止了回显功能 关闭   ECHOPRT 向后删除回显的字符 关闭   FLUSHO 输出被刷新(未使用)    ICANON 规范模式输入 打开   IEXTEN 启动对输入字符的扩展 打开   ISIG 启动信号产生字符 打开   NOFLASH 禁止在INTR QUIT SUSP上进行刷新 关闭   PENDIN 在下一次读操作时重新显示等待的输入(未实现) (关闭)   TOSTOP 为后台输出产生SIGTTOU信号 关闭   XCASE 规范大小写表示(未实现) (关闭)    optional_actions    选项 含义     TCSANOW 修改立刻得到生效   TCSADRAIN 当所有当前处于排队中的输出已将传送到终端之后，修改得到生效   TCSAFLUSH 产生的效果同TCSADRAIN，但除此之外当标志生效时那些仍然等待处理的数据将被丢弃    终端特殊字符    字符 c_cc下标 描述 默认设定 相关标志位掩码     CR 无 回车符。这个字符会传递给正在读取输入的进程。在默认设定了ICRNL(在输入中将CR映射为NL)标志的规范模式下。这个字符首先被转换为一个换行符(ASCII码，0x0A)然后再传递给读取输入的进程。如果设定了IGNCR(忽略CR)标志，那么就在输入上忽略这个字符，此时必须用真正的换行符来作为一行的结束。输出一个CR字符将导致终端将光标移动到一行的开始处 ^M ICANON IGNCR ICRNL OPOST OCRNL ONOCR   DISCARD VDISCARD 丢弃输出字符，Linux未实现 ^O    EOF VEOF 传统模式下的文件结尾字符(Ctrl\x2bD)。在一行的开始处输入这个字符会导致终端上读取输入的进程检测到文件结尾的情况(即read()返回0)。如果不在一行开始处，而在启停地方输入这个字符，那么该字符会立刻导致read()完成调用，返回这一行中目前为止读取到的字符数。这两种情况下EOF字符本身不会传递给读取进程 ^D ICANON   EOL VEOL 附加的行分隔字符，对于规范模式下的输入，其表现如同换行符一样，用来终止一行输入并使改行对读取进程可见。默认情况下这些字符是未定义的如果定义了它们，它们是会被发送给读取进程的。  ICANON   EOL2 VEOL2 同上，只不过只有当设置了IEXTEN标志时才能正常工作  ICANON IEXTEN   ERASE VERASE 在规范模式下，输入ERASE字符会擦除当前行中前一个输入的字符，被擦除的字符以及ERASE字符本身都不会传递给读取输入的进程 ^?",
    "inLanguage" : "en-us",
    "author" : "Mr.wei",
    "creator" : "Mr.wei",
    "publisher": "Mr.wei",
    "accountablePerson" : "Mr.wei",
    "copyrightHolder" : "Mr.wei",
    "copyrightYear" : "2019",
    "datePublished": "2019-09-03 10:48:46 \x2b0800 CST",
    "dateModified" : "2019-09-03 10:48:46 \x2b0800 CST",
    "url" : "http:\/\/blog.mr-wei.cn\/2019\/linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BB%88%E7%AB%AF\/",
    "wordCount" : "950",
    "keywords" : [ "APUE", "Mr.wei"]
}
</script>

</head>

  


  <body class="">
    <div class="wrapper">
        <nav class="navbar">
    <div class="container">
        <div class="navbar-header header-logo">
        	<a href="javascript:void(0);" class="theme-switch"><i class="iconfont icon-xihuan"></i></a>&nbsp;<a href="http://blog.mr-wei.cn">Mr.wei</a>
        </div>
        <div class="menu navbar-right">
                
                
                <a class="menu-item" href="/posts/" title="">Blog</a>
                
                <a class="menu-item" href="http://balance.mr-wei.cn" title="">BalanceCar</a>
                
                <a class="menu-item" href="/categories/" title="">Categories</a>
                
                <a class="menu-item" href="/tags/" title="">Tags</a>
                
                <a class="menu-item" href="/about/" title="About">About</a>
                
        </div>
    </div>
</nav>
<nav class="navbar-mobile" id="nav-mobile" style="display: none">
     <div class="container">
        <div class="navbar-header">
            <div>  <a href="javascript:void(0);" class="theme-switch"><i class="iconfont icon-xihuan"></i></a>&nbsp;<a href="http://blog.mr-wei.cn">Mr.wei</a></div>
            <div class="menu-toggle">
                <span></span><span></span><span></span>
            </div>
        </div>
     
          <div class="menu" id="mobile-menu">
                
                
                <a class="menu-item" href="/posts/" title="">Blog</a>
                
                <a class="menu-item" href="http://balance.mr-wei.cn" title="">BalanceCar</a>
                
                <a class="menu-item" href="/categories/" title="">Categories</a>
                
                <a class="menu-item" href="/tags/" title="">Tags</a>
                
                <a class="menu-item" href="/about/" title="About">About</a>
                
        </div>
    </div>
</nav>







    	 <main class="main">
          <div class="container">
      		
<article class="post-warp" itemscope itemtype="http://schema.org/Article">
    <header class="post-header">
        <h1 class="post-title" itemprop="name headline">Linux系统编程之终端</h1>
        <div class="post-meta">
                Written by <a itemprop="name" href="http://blog.mr-wei.cn" rel="author">Mr.wei</a> with ♥ 
                <span class="post-time">
                on <time datetime=2019-09-03 itemprop="datePublished">September 3, 2019</time>
                </span>
                in
                <i class="iconfont icon-folder"></i>
                <span class="post-category">
                        
                </span>
        </div>
    </header>
    <div class="post-content">
        

        

        
        
     
          
          
          

          
          
          

          

<h1 id="终端驱动程序的两种模式">终端驱动程序的两种模式</h1>

<ul>
<li><p>规范模式 : 在此种模式下，终端的输入是按照行来处理的，而且可进行编辑操作。每一行都由换行符来结束，当用户按下回车键时可产生换行符。在终端上执行的read()调用只会在一行输入完成之后才回返回，且最多只返回一行。如果read()请求的字节数少于当前行中的可用字节，那么剩下的字节在下次read()调用时可用。</p></li>

<li><p>非规范模式 : 终端输入不会被装配成行。不需要用户按下回车键就能读取到单个字符。c_cc数组中的元素TIME以十分之一秒为单位来指定超时时间。元素MIN指定了被读取字节数的最小值。</p>

<ul>
<li>MIN==0,TIME==0(轮询读取)</li>
</ul>

<p>如果在调用过程中有数据可用，那么read()将立刻返回可用的字节数和所请求的字节数中较小的那个值。如果没有数据可用，read()将立即返回0。</p>

<ul>
<li>MIN&gt;0,TIME==0(阻塞式读取,open不指定O_NONBLOCK标志)</li>
</ul>

<p>read()会阻塞，直到请求的字节数得到满足或者读取到了MIN个字节，此时就返回这两者中较小的那一个。</p>

<ul>
<li>MIN==0,TIME&gt;0(带有超时机制的读操作,open不指定O_NONBLOCK标志)</li>
</ul>

<p>调用read()时会启动一个定时器。当至少有一个字节可用，或者当经历了TIME个十分之一秒后，read()会立刻返回。在后一种情况下read()将返回0。</p>

<ul>
<li>MIN&gt;0,TIME&gt;0(既有超时机制又有最小读取字节要求,open不指定O_NONBLOCK标志)</li>
</ul>

<p>当输入的首个字节可用后，之后每接收到一个字节就重启定时器。如果读到了MIN个字节，或者请求的字节数已经读取完毕，此时read()会返回两者间较小的那个值。或者当接收连续字节之间的时隙超过TIME个十分之一秒，此时read()会返回0。因为定时器只会初始字节可用后才启动，因此至少可以返回1个字节。</p></li>
</ul>

<!-- more -->

<h1 id="获取和修改终端属性">获取和修改终端属性</h1>

<pre><code class="language-C">#include &lt;termios.h&gt;
int tcgetattr(int fd,struct termios *termios_p);//获取终端属性
int tcsetattr(int fd,int optional_actions,const struct termios *termios_p);	//设置终端属性
//fd为终端文件描述符，如果fd不指向终端，调用函数会失败并伴随错误码ENOTTY
//termios_p为指向结构体termios的指针用来记录终端的各项属性
//optional_action 决定设置的属性何时生效
//函数调用成功返回0，失败返回-1
</code></pre>

<h2 id="termios结构体详解">termios结构体详解</h2>

<pre><code class="language-C">struct termoios{
    tcflag_t c_iflag;		//控制终端输入的标志
    tcflag_t c_oflag;		//控制终端输出的标志
    tcflag_t c_cflag;		//控制终端线速的硬件控制相关的标志
    tcflag_t c_lflag;		//控制终端输入的用户界面的标志
    cc_t 	 c_line;		//指定终端的行规程
    cc_t     c_cc[NCCS];	//包含终端的特殊字符，以及用来控制非规范模式下输入操作的相关字段
    speed_t  c_ispeed;		//Linux未使用
    speed_t  c_ospeed;		//Linux未使用
    }
}
</code></pre>

<h3 id="c-iflag">c_iflag</h3>

<table>
<thead>
<tr>
<th>标志</th>
<th>描述</th>
<th>默认设置</th>
</tr>
</thead>

<tbody>
<tr>
<td>BRKINT</td>
<td>在BREAK状态下发出信号终端</td>
<td>打开</td>
</tr>

<tr>
<td></td>
<td>在输入中将CR映射为NL</td>
<td>打开</td>
</tr>

<tr>
<td></td>
<td>忽略BREAK状态</td>
<td>关闭</td>
</tr>

<tr>
<td>IGNCR</td>
<td>在输入中忽略CR</td>
<td>关闭</td>
</tr>

<tr>
<td></td>
<td>忽略有奇偶校验错误的字符</td>
<td>关闭</td>
</tr>

<tr>
<td></td>
<td>终端输入队列满时发出响铃(未使用)</td>
<td>(打开)</td>
</tr>

<tr>
<td>INLCR</td>
<td>在输入中将NL映射为CR</td>
<td>关闭</td>
</tr>

<tr>
<td></td>
<td>开启输入奇偶校验检查</td>
<td>关闭</td>
</tr>

<tr>
<td></td>
<td>从输入字符中去掉最高位</td>
<td>关闭</td>
</tr>

<tr>
<td>IUTF8</td>
<td>输入为UTF-8编码</td>
<td>关闭</td>
</tr>

<tr>
<td></td>
<td>如果IEXTEN也同时设置，则在输入中将大写字符映射为小写字符</td>
<td>关闭</td>
</tr>

<tr>
<td>I</td>
<td>允许用任意字符来重启已停止的输出</td>
<td>关闭</td>
</tr>
</tbody>
</table>

<h3 id="c-oflag">c_oflag</h3>

<table>
<thead>
<tr>
<th>标志</th>
<th>描述</th>
<th>默认设置</th>
</tr>
</thead>

<tbody>
<tr>
<td>BSDLY</td>
<td>退格延时掩码(BS0、BS1)</td>
<td>BS0</td>
</tr>

<tr>
<td>CRDLY</td>
<td>CR延时掩码(CR0、CR1、CR2、CR3)</td>
<td>CR0</td>
</tr>

<tr>
<td>FFDLY</td>
<td>换页符延时掩码(FF0、FF1)</td>
<td>FF0</td>
</tr>

<tr>
<td>NLDLY</td>
<td>换行延时掩码(NL0、NL1)</td>
<td>NL0</td>
</tr>

<tr>
<td>OCRNL</td>
<td>在输出中将CR映射为NL</td>
<td>关闭</td>
</tr>

<tr>
<td>OFDEL</td>
<td>用DEL作为填充符否则用NULL作为填充符</td>
<td>关闭</td>
</tr>

<tr>
<td>OFILL</td>
<td>采用填充符作为延时而不是定时延时</td>
<td>关闭</td>
</tr>

<tr>
<td>OLCUC</td>
<td>在输出中将小写字符映射为大写字符</td>
<td>关闭</td>
</tr>

<tr>
<td>ONLCR</td>
<td>在输出中将NL映射为CR-NL</td>
<td>打开</td>
</tr>

<tr>
<td>ONLRET</td>
<td>假定NL执行CR的功能</td>
<td>关闭</td>
</tr>

<tr>
<td>ONOCR</td>
<td>如果已经在一行的开始就不输出CR</td>
<td>关闭</td>
</tr>

<tr>
<td>OPOST</td>
<td>执行输出后续处理</td>
<td>打开</td>
</tr>

<tr>
<td></td>
<td>水平制表符延时掩码(TAB0、TAB1、TAB2、TAB3)</td>
<td>TAB0</td>
</tr>

<tr>
<td>VTDLY</td>
<td>垂直制表符延时掩码(VT0、VT1)</td>
<td>VT0</td>
</tr>
</tbody>
</table>

<h3 id="c-cflag">c_cflag</h3>

<table>
<thead>
<tr>
<th>标志</th>
<th>描述</th>
<th>默认设置</th>
</tr>
</thead>

<tbody>
<tr>
<td>CBAUD</td>
<td>波特率掩码</td>
<td>B38400</td>
</tr>

<tr>
<td>CBAUDEX</td>
<td>扩展波特率掩码针速率对大于38400</td>
<td>关闭</td>
</tr>

<tr>
<td>CIBAUD</td>
<td>输入波特率(未使用)</td>
<td>关闭</td>
</tr>

<tr>
<td>CLOCAL</td>
<td>忽略调制解调器的状态行</td>
<td>关闭</td>
</tr>

<tr>
<td>CMSPAR</td>
<td>使用奇偶校验</td>
<td>关闭</td>
</tr>

<tr>
<td>CREAD</td>
<td>允许输入被接收</td>
<td>打开</td>
</tr>

<tr>
<td>CRTSCTS</td>
<td>启动CTS/RTS流控</td>
<td>关闭</td>
</tr>

<tr>
<td>CSIZE</td>
<td>字符大小掩码(CS5、CS6、CS7、CS8)</td>
<td>CS8</td>
</tr>

<tr>
<td>CSTOPB</td>
<td>每个字符使用两个停止位，否则使用1个</td>
<td>关闭</td>
</tr>

<tr>
<td>HUPCL</td>
<td>在上次关闭时挂起</td>
<td>打开</td>
</tr>

<tr>
<td>PARENB</td>
<td>启动奇偶校验</td>
<td>关闭</td>
</tr>

<tr>
<td>PARODD</td>
<td>使用奇数校验否则使用偶数校验</td>
<td>关闭</td>
</tr>
</tbody>
</table>

<h3 id="c-lflag">c_lflag</h3>

<table>
<thead>
<tr>
<th>标志</th>
<th>描述</th>
<th>默认设置</th>
</tr>
</thead>

<tbody>
<tr>
<td>ECHO</td>
<td>回显输入字符</td>
<td>打开</td>
</tr>

<tr>
<td>ECHOCTL</td>
<td>以可视方式回显控制字符</td>
<td>打开</td>
</tr>

<tr>
<td>ECHOE</td>
<td>以可视方式回显ERASE字符</td>
<td>打开</td>
</tr>

<tr>
<td>ECHOK</td>
<td>以可视方式回显KILL字符</td>
<td>打开</td>
</tr>

<tr>
<td>ECHOKE</td>
<td>在回显KILL字符后不输出新的行</td>
<td>打开</td>
</tr>

<tr>
<td>ECHONL</td>
<td>回显NL即使禁止了回显功能</td>
<td>关闭</td>
</tr>

<tr>
<td>ECHOPRT</td>
<td>向后删除回显的字符</td>
<td>关闭</td>
</tr>

<tr>
<td>FLUSHO</td>
<td>输出被刷新(未使用)</td>
<td></td>
</tr>

<tr>
<td>ICANON</td>
<td>规范模式输入</td>
<td>打开</td>
</tr>

<tr>
<td>IEXTEN</td>
<td>启动对输入字符的扩展</td>
<td>打开</td>
</tr>

<tr>
<td>ISIG</td>
<td>启动信号产生字符</td>
<td>打开</td>
</tr>

<tr>
<td>NOFLASH</td>
<td>禁止在INTR QUIT SUSP上进行刷新</td>
<td>关闭</td>
</tr>

<tr>
<td>PENDIN</td>
<td>在下一次读操作时重新显示等待的输入(未实现)</td>
<td>(关闭)</td>
</tr>

<tr>
<td>TOSTOP</td>
<td>为后台输出产生SIGTTOU信号</td>
<td>关闭</td>
</tr>

<tr>
<td>XCASE</td>
<td>规范大小写表示(未实现)</td>
<td>(关闭)</td>
</tr>
</tbody>
</table>

<h2 id="optional-actions">optional_actions</h2>

<table>
<thead>
<tr>
<th>选项</th>
<th>含义</th>
</tr>
</thead>

<tbody>
<tr>
<td>TCSANOW</td>
<td>修改立刻得到生效</td>
</tr>

<tr>
<td>TCSADRAIN</td>
<td>当所有当前处于排队中的输出已将传送到终端之后，修改得到生效</td>
</tr>

<tr>
<td>TCSAFLUSH</td>
<td>产生的效果同TCSADRAIN，但除此之外当标志生效时那些仍然等待处理的数据将被丢弃</td>
</tr>
</tbody>
</table>

<h2 id="终端特殊字符">终端特殊字符</h2>

<table>
<thead>
<tr>
<th>字符</th>
<th>c_cc下标</th>
<th align="left">描述</th>
<th>默认设定</th>
<th>相关标志位掩码</th>
</tr>
</thead>

<tbody>
<tr>
<td>CR</td>
<td>无</td>
<td align="left">回车符。这个字符会传递给正在读取输入的进程。在默认设定了ICRNL(在输入中将CR映射为NL)标志的规范模式下。这个字符首先被转换为一个换行符(ASCII码，0x0A)然后再传递给读取输入的进程。如果设定了IGNCR(忽略CR)标志，那么就在输入上忽略这个字符，此时必须用真正的换行符来作为一行的结束。输出一个CR字符将导致终端将光标移动到一行的开始处</td>
<td>^M</td>
<td>ICANON IGNCR ICRNL OPOST OCRNL ONOCR</td>
</tr>

<tr>
<td>DISCARD</td>
<td>VDISCARD</td>
<td align="left">丢弃输出字符，Linux未实现</td>
<td>^O</td>
<td></td>
</tr>

<tr>
<td>EOF</td>
<td>VEOF</td>
<td align="left">传统模式下的文件结尾字符(Ctrl+D)。在一行的开始处输入这个字符会导致终端上读取输入的进程检测到文件结尾的情况(即read()返回0)。如果不在一行开始处，而在启停地方输入这个字符，那么该字符会立刻导致read()完成调用，返回这一行中目前为止读取到的字符数。这两种情况下EOF字符本身不会传递给读取进程</td>
<td>^D</td>
<td>ICANON</td>
</tr>

<tr>
<td>EOL</td>
<td>VEOL</td>
<td align="left">附加的行分隔字符，对于规范模式下的输入，其表现如同换行符一样，用来终止一行输入并使改行对读取进程可见。默认情况下这些字符是未定义的如果定义了它们，它们是会被发送给读取进程的。</td>
<td></td>
<td>ICANON</td>
</tr>

<tr>
<td>EOL2</td>
<td>VEOL2</td>
<td align="left">同上，只不过只有当设置了IEXTEN标志时才能正常工作</td>
<td></td>
<td>ICANON IEXTEN</td>
</tr>

<tr>
<td>ERASE</td>
<td>VERASE</td>
<td align="left">在规范模式下，输入ERASE字符会擦除当前行中前一个输入的字符，被擦除的字符以及ERASE字符本身都不会传递给读取输入的进程</td>
<td>^?</td>
<td>ICANON</td>
</tr>

<tr>
<td>INTR</td>
<td>VINTR</td>
<td align="left">中断字符。如果设置了ISIG标志，输入这个字符会产生一个中断信号，并发送给终端的前台进程组，INTR字符本身是不会发送给读取输入的进程的</td>
<td>^C</td>
<td>ISIG</td>
</tr>

<tr>
<td>KILL</td>
<td>VKILL</td>
<td align="left">KILL是擦除行字符，在规范模式下，输入这个字符使得当前这行输入被丢弃，即到目前位置输入的字符连同KILL字符本身都不会传递给读取输入的进程</td>
<td>^U</td>
<td>ICANON</td>
</tr>

<tr>
<td>LNEXT</td>
<td>VLNEXT</td>
<td align="left">下一个字符的字面化表示。输入LNEXT字符后下一个字符将以字面形式处理，避免终端驱动程序指向任何针对特殊字符的解释处理</td>
<td>^V</td>
<td>ICANON IEXTEN</td>
</tr>

<tr>
<td>NL</td>
<td></td>
<td align="left">换行符，在规范模式下，该字符终结一行输入。NL字符本身是会包含在行中返回给读取进程的。规范模式下CR字符通常会转换为NL字符，输出一个NL字符导致终端将光标移动到下一行。如果设置了OPOST和ONLCR标志，那么在输出中一个换行符就会映射为一个2字节符号序列(CR和NL)</td>
<td>^J</td>
<td>ICANON INLCR ECHONL OPOST ONLCR ONLRET</td>
</tr>

<tr>
<td>QUIT</td>
<td>VQUIT</td>
<td align="left">如果设置了ISIG标志，输入QUIT字符会产生一个退出信号并发送到终端的前台进程组中，QUIT字符本身不会传递给读取进程</td>
<td>^</td>
<td>ISIG</td>
</tr>

<tr>
<td>REPRINT</td>
<td>VREPRINT</td>
<td align="left">重新打印输入。在规范模式下，如果设置了IEXTEN标志，输入该字符会使得当前的输入行重新显示在终端上</td>
<td>^R</td>
<td>ICANON IEXTEN ECHO</td>
</tr>

<tr>
<td>START</td>
<td>VSTART</td>
<td align="left">开始输出字符</td>
<td>^Q</td>
<td>IXON IXOFF</td>
</tr>

<tr>
<td>STOP</td>
<td>VSTOP</td>
<td align="left">停止输出字符</td>
<td>^S</td>
<td>IXON IXOFF</td>
</tr>

<tr>
<td>SUSP</td>
<td>VSUSP</td>
<td align="left">暂停字符</td>
<td>^Z</td>
<td>ISIG</td>
</tr>

<tr>
<td>WERASE</td>
<td>VWERASE</td>
<td align="left">擦除一个字符</td>
<td>^W</td>
<td>ICANON IEXTEN</td>
</tr>
</tbody>
</table>

<h2 id="终端线速">终端线速</h2>

<pre><code class="language-C">#include &lt;termios.h&gt;
speed_t cfgetispeed(const struct termios *termios_p);
speed_t cfgetospeed(const struct termios *termios_p);
int cfsetospeed(struct termios *termios_p,speed_t speed);
int cfsetispeed(struct termios *termios_p,speed_t speed);
</code></pre>

<h2 id="行控制">行控制</h2>

<pre><code class="language-C">#include &lt;termios.h&gt;
int tcsendbreak(int fd,int duration);//通过传输连续的0比特流产生一个BREAK状态参数duration指定了传输持续时间。duration=0那么传输0比特序列的时间将持续0.25，如果大于0则持续duration个ms
int tcdrain(int fd);，
int tcflush(int fd,int queue_selector);////丢弃终端输入队列，终端输出队列或同时刷新两个队列，TCIFLUSH、TCOFLUSH、TCIOFLUSH
int tcflow(int fd,int action);//控制计算机和终端之间的数据流向，TCOOFF暂停终端上的输出、TCOON恢复终端上的输出、TCIOFF传送一个STOP字符给终端、TCION传送一个START字符给终端
</code></pre>

<h2 id="终端标识符">终端标识符</h2>

<pre><code class="language-C">#include &lt;unistd.h&gt;
int isatty(int fd);//fd是终端返回1，否则返回0
char *ttyname(int fd);//返回终端的名称
</code></pre>

<h1 id="示例代码一-非规范模式轮询">示例代码一(非规范模式轮询)</h1>

<ul>
<li><p>tty.h</p>

<pre><code class="language-C">#ifndef __TTY_H
#define __TTY_H
int Opentty(const char *device);
int Closetty(int fd);
int Settty(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity);
int Writetty(int fd,unsigned char *buffer,int length);
int Readtty(int fd ,unsigned char *buffer,int length);
#endif
</code></pre></li>

<li><p>tty.c</p>

<pre><code class="language-C">#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;unistd.h&gt;
#include &lt;termios.h&gt;
#include &lt;stdio.h&gt;
int Opentty(const char *device)
{
int fd;
    
fd = open(device,O_RDWR|O_NOCTTY);
if(fd == -1)
{
    printf(&quot;open %s failed !\n&quot;,device);
    return -1;
}
return fd;
}
int Closetty(int fd)
{
	if(!isatty(fd))
	{
 	printf(&quot;fd not a termios !\n&quot;);
	}
	fd = close(fd);
	if(fd == -1)
	{
    printf(&quot;close fd failed !\n&quot;);
	}
	return 1;
}
int Settty(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)
{
struct termios options;
if(tcgetattr(fd,&amp;options) != 0)
{
    printf(&quot;get termios attr failed !\n&quot;);
    return -1;
}
switch(speed)
{
    case 115200:
    cfsetispeed(&amp;options,B115200);
    cfsetospeed(&amp;options,B115200);
    break;
    case 19200:
    cfsetispeed(&amp;options,B19200);
    cfsetospeed(&amp;options,B19200);
    break;
    case 9600:
    cfsetispeed(&amp;options,B9600);
    cfsetospeed(&amp;options,B9600);
    break;
    case 4800:
    cfsetispeed(&amp;options,B4800);
    cfsetospeed(&amp;options,B4800);
    break;
    case 2400:
    cfsetispeed(&amp;options,B2400);
    cfsetospeed(&amp;options,B2400);
    break;
    default:
    break;
}
	options.c_cflag |= CLOCAL;//忽略调制解调器的运行状态
	options.c_cflag |= CREAD;//允许输入被接收
	switch(flow_ctrl)
	{
    case 0:
    options.c_cflag &amp;= ~CRTSCTS;//不使用流控制
    break;
    case 1:
    options.c_cflag |= CRTSCTS;//使用硬件流控
    break;
    default:
    break;
	}
options.c_cflag &amp;= ~CSIZE;    
switch (databits)    
{      
    case 5:    
            options.c_cflag |= CS5;    
    break;    
    case 6:    
            options.c_cflag |= CS6;    
    break;    
    case 7:        
            options.c_cflag |= CS7;    
    break;    
    case 8:        
            options.c_cflag |= CS8;    
    break;      
    default: 
            options.c_cflag |= CS8;    
    break;     
}  
switch (parity)    
{      
    case 'n':    
    case 'N': //无奇偶校验位。
            options.c_cflag &amp;= ~PARENB;     
            options.c_iflag &amp;= ~INPCK;        
    break;     
    case 'o':      
    case 'O'://设置为奇校验        
            options.c_cflag |= (PARODD | PARENB);     
            options.c_iflag |= INPCK;                 
    break;     
    case 'e':     
    case 'E'://设置为偶校验      
            options.c_cflag |= PARENB;           
            options.c_cflag &amp;= ~PARODD;           
            options.c_iflag |= INPCK;          
    break;    
    case 's':    
    case 'S': //设置为空格     
            options.c_cflag &amp;= ~PARENB;    
            options.c_cflag &amp;= ~CSTOPB;    
    break;     
    default:      
    break;     
}     
switch (stopbits)    
{      
    case 1:       
            options.c_cflag &amp;= ~CSTOPB; 
    break;     
    case 2:       
            options.c_cflag |= CSTOPB;
    break;    
    default:
    break;
}    
options.c_oflag &amp;= ~OPOST;//关闭输出后续处理，以原始数据输出
options.c_lflag &amp;= ~(ICANON | ISIG | IEXTEN | ECHO| ECHOE);//
options.c_iflag &amp;= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR |INPCK | ISTRIP | IXON | PARMRK);//
options.c_cc[VTIME]= 0;//超时时间 n*1/10 S
options.c_cc[VMIN] = 0;//至少读取 m字节前阻塞
tcflush(fd,TCIOFLUSH); 
if (tcsetattr(fd,TCSANOW,&amp;options) != 0)      
{    
    printf(&quot;termios set failed !\n&quot;);    
    return -1;     
}    
return 1;     

}
int Writetty(int fd,unsigned char *buffer,int length)
{
if(!isatty(fd))
	{
 	printf(&quot;fd not a termios !\n&quot;);
	}
	length = write(fd,buffer,length);
	return length;
}
int Readtty(int fd,unsigned char *buffer,int length)
{
if(!isatty(fd))
	{
 	printf(&quot;fd not a termios !\n&quot;);
	}
length = read(fd,buffer,length);
return length;
}
</code></pre></li>

<li><p>main.c</p>

<pre><code class="language-C">#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;unistd.h&gt;
#include &lt;termios.h&gt;
#include &lt;stdio.h&gt;
#include &quot;tty.h&quot;
unsigned char TxBuffer[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
unsigned char RxBuffer[20];
int main(void)
{
	int fd;
	int readnum,writenum;
	int error;
	fd = Opentty(&quot;/dev/ttyUSB0&quot;);
	if(fd == -1)
		return 0;
	do{
   error = Settty(fd,115200,0,8,1,'N');
	}while(error == -1);
	writenum = Writetty(fd,TxBuffer,20);
	if(writenum != 20)
		printf(&quot;Write failed&quot;);
	printf(&quot;Read data!\n&quot;);
	while(1)
	{
    readnum = Readtty(fd,RxBuffer,20);	//这里不会阻塞，当没有数据时read()函数返回0
    if(readnum &gt;0)
    	printf(&quot;read num is :%d\n&quot;,readnum);
		
	}
	Closetty(fd);
return 0;
}
</code></pre></li>

<li><p>Makefile</p>

<pre><code class="language-make">######################################
#
######################################
#source file
SOURCE  := $(wildcard *.c) $(wildcard *.cpp)
OBJS    := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE)))
  
#target you can change test to what you want
TARGET  := main
  
#compile and lib parameter
CC      := gcc
LIBS    :=
LDFLAGS :=
DEFINES :=
INCLUDE := -I.
CFLAGS  := -g -Wall -O3 $(DEFINES) $(INCLUDE)
CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_H
  
  
#i think you should do anything here
.PHONY : everything objs clean veryclean rebuild
  
everything : $(TARGET)
  
all : $(TARGET)
  
objs : $(OBJS)
  
rebuild: veryclean everything
                
clean :
	rm -fr *.so
	rm -fr *.o
    
veryclean : clean
	rm -fr $(TARGET)
  
$(TARGET) : $(OBJS)
	$(CC) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LIBS)
</code></pre></li>
</ul>

<h1 id="参考资料">参考资料</h1>

<ul>
<li><font size=6>Linux/UNIX系统编程手册</font></li>
</ul>

    </div>

    <div class="post-copyright">
             
            <p class="copyright-item">
                <span>Author:</span>
                <span>Mr.wei </span>
                </p>
            
           
             
            <p class="copyright-item">
                    <span>Link:</span>
                    <a href=http://blog.mr-wei.cn/2019/linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BB%88%E7%AB%AF/>http://blog.mr-wei.cn/2019/linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BB%88%E7%AB%AF/</span>
            </p>
            
             
            <p class="copyright-item lincese">
                本文采用<a rel="license" href="http://creativecommons.org/licenses/by-nc/4.0/" #target="_blank">知识共享署名-非商业性使用 4.0 国际许可协议</a>进行许可
            </p>
            
    </div>

  
    <div class="post-tags">
        
            <section>
            <i class="iconfont icon-tag"></i>Tag(s): 
            
            <span class="tag"><a href="http://blog.mr-wei.cn/tags/apue/">
                    #APUE</a></span>
            
            </section>
        
        <section>
                <a href="javascript:window.history.back();">back</a></span> · 
                <span><a href="http://blog.mr-wei.cn">home</a></span>
        </section>
    </div>

    <div class="post-nav">
        
        <a href="http://blog.mr-wei.cn/2019/shell-%E9%80%9A%E9%85%8D%E7%AC%A6/" class="prev" rel="prev" title="shell 通配符"><i class="iconfont icon-left"></i>&nbsp;shell 通配符</a>
         
        
        <a href="http://blog.mr-wei.cn/2019/cadence-allegro%E5%88%B6%E4%BD%9C%E9%80%9A%E5%AD%94%E7%84%8A%E7%9B%98/" class="next" rel="next" title="Cadence Allegro制作通孔焊盘">Cadence Allegro制作通孔焊盘&nbsp;<i class="iconfont icon-right"></i></a>
        
    </div>

    <div class="post-comment">
          
                 
          
    </div>
</article>
          </div>
		   </main>
      <footer class="footer">
    <div class="copyright">
        &copy;
        
        <span itemprop="copyrightYear">2018 - 2019</span>
        
        <span class="with-love">
    	 <i class="iconfont icon-love"></i> 
         </span>
         
            <span class="author" itemprop="copyrightHolder"><a href="http://blog.mr-wei.cn">Mr.wei</a> | </span> 
         

         
            <a href="http://www.miibeian.gov.cn/" target="_blank" rel="external nofollow">冀ICP备 - 18032379号 </a> |
         
		  <span>Powered by <a href="https://gohugo.io/" target="_blank" rel="external nofollow">Hugo</a> & <a href="https://github.com/liuzc/leaveit" target="_blank" rel="external nofollow">LeaveIt</a></span> 
    </div>

	
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
        tex2jax: {
            inlineMath: [['$','$'], ['\\(','\\)']],
            displayMath: [['$$','$$'], ['\[','\]']],
            processEscapes: true,
            processEnvironments: true,
            skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
            TeX: {
                equationNumbers: { autoNumber: "AMS" },
                extensions: ["AMSmath.js", "AMSsymbols.js"]
            }
        }
    });
</script>
<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"></script>
	
	

</footer>












    
    
    <script src="/js/vendor_no_gallery.min.js" async=""></script>
    
  



     </div>
  </body>
</html>
